/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "scan_service_ability.h"

#include <cerrno>
#include <ctime>
#include <string>
#include <sys/time.h>
#include <thread>
#include <unistd.h>

#include "accesstoken_kit.h"
#include "array_wrapper.h"
#include "core_service_client.h"
#include "int_wrapper.h"
#include "ipc_skeleton.h"
#include "iservice_registry.h"
#include "napi_scan_utils.h"
#include "scan_constant.h"
#include "scan_log.h"
#include "scan_util.h"
#include "scanner_info.h"
#include "string_wrapper.h"
#include "system_ability.h"
#include "system_ability_definition.h"
#include "want_params_wrapper.h"

namespace OHOS::Scan {
using namespace std;
using namespace OHOS::HiviewDFX;
using namespace Security::AccessToken;

const int64_t INIT_INTERVAL = 5000L;
const uint32_t ASYNC_CMD_DELAY = 10;

static const std::string PERMISSION_NAME_SCAN = "ohos.permission.SCAN";
static const std::string PERMISSION_NAME_SCAN_JOB = "ohos.permission.MANAGE_SCAN_JOB";
static const std::string SCAN_DEVICE_FOUND_TCP = "scanDeviceFoundTCP";
static const std::string SCAN_DEVICE_FOUND_LIBUSB = "scanDeviceFoundLibUSB";
static const std::string SCAN_INIT_EVENT = "scanInitEvent";

static const std::string DEVICE_EVENT_TYPE = "deviceStateChange";
static const std::string GET_FRAME_RES_EVENT_TYPE = "getFrameResult";

std::map<std::string, sptr<IScanCallback>> OHOS::Scan::ScanServiceAbility::registeredListeners_;

REGISTER_SYSTEM_ABILITY_BY_ID(ScanServiceAbility, SCAN_SERVICE_ID, true);

std::mutex ScanServiceAbility::instanceLock_;
sptr<ScanServiceAbility> ScanServiceAbility::instance_;
std::shared_ptr<AppExecFwk::EventHandler> ScanServiceAbility::serviceHandler_;

ScanServiceAbility::ScanServiceAbility(int32_t systemAbilityId, bool runOnCreate)
    : SystemAbility(systemAbilityId, runOnCreate), state_(ServiceRunningState::STATE_NOT_START)
{}

ScanServiceAbility::~ScanServiceAbility()
{
    SCAN_HILOGE("~ScanServiceAbility state_  is %{public}d.", static_cast<int>(state_));
}

sptr<ScanServiceAbility> ScanServiceAbility::GetInstance()
{
    if (instance_ == nullptr) {
        std::lock_guard<std::mutex> autoLock(instanceLock_);
        if (instance_ == nullptr) {
            instance_ = new ScanServiceAbility(SCAN_SERVICE_ID, true);
        }
    }
    return instance_;
}

int32_t ScanServiceAbility::ServiceInit()
{
    bool ret = Publish(ScanServiceAbility::GetInstance());
    if (!ret) {
        SCAN_HILOGE("ScanServiceAbility Publish failed.");
        return E_SCAN_SERVER_FAILURE;
    }
    state_ = ServiceRunningState::STATE_RUNNING;
    SCAN_HILOGE("state_ is %{public}d.", static_cast<int>(state_));
    SCAN_HILOGI("Init ScanServiceAbility success.");
    int32_t scanVersion = 0;
    InitScan(scanVersion);
    return ERR_OK;
}

void ScanServiceAbility::OnStart()
{
    SCAN_HILOGI("ScanServiceAbility::Enter OnStart.");
    if (instance_ == nullptr) {
        instance_ = this;
    }
    if (state_ == ServiceRunningState::STATE_RUNNING) {
        SCAN_HILOGI("ScanServiceAbility is already running.");
        return;
    }

    InitServiceHandler();
    int32_t ret = ServiceInit();
    if (ret != ERR_OK) {
        auto callback = [=]() { ServiceInit(); };
        serviceHandler_->PostTask(callback, INIT_INTERVAL);
        SCAN_HILOGE("ScanServiceAbility Init failed. Try again 5s later");
        return;
    }
    state_ = ServiceRunningState::STATE_RUNNING;
    return;
}

void ScanServiceAbility::InitServiceHandler()
{
    SCAN_HILOGI("InitServiceHandler started.");
    if (serviceHandler_ != nullptr) {
        SCAN_HILOGI("InitServiceHandler already init.");
        return;
    }
    std::shared_ptr<AppExecFwk::EventRunner> runner = AppExecFwk::EventRunner::Create("ScanServiceAbility");
    serviceHandler_ = std::make_shared<AppExecFwk::EventHandler>(runner);
    SCAN_HILOGI("InitServiceHandler succeeded.");
}

void ScanServiceAbility::ManualStart()
{
    if (state_ != ServiceRunningState::STATE_RUNNING) {
        SCAN_HILOGI("ScanServiceAbility restart.");
        OnStart();
    }
}

void ScanServiceAbility::OnStop()
{
    SCAN_HILOGI("OnStop started.");
    if (state_ != ServiceRunningState::STATE_RUNNING) {
        return;
    }
    serviceHandler_ = nullptr;
    state_ = ServiceRunningState::STATE_NOT_START;
    SCAN_HILOGI("OnStop end.");
}

//to do
int32_t ScanServiceAbility::InitScan(int32_t &scanVersion)
{
    ManualStart();
    if (!CheckPermission(PERMISSION_NAME_SCAN)) {
        SCAN_HILOGE("no permission to access scan service");
        return E_SCAN_NO_PERMISSION;
    }
    ExitScan();
    SCAN_HILOGE("ScanServiceAbility InitScan start");
    SANE_Status status = sane_init(&scanVersion, nullptr);
    if (status != SANE_STATUS_GOOD) {
        SCAN_HILOGE("sane_init failed, reason: [%{public}s]", sane_strstatus(status));
        return ScanUtil::ConvertErro(status);
    }
    SendInitEvent(scanVersion,SCAN_INIT_EVENT);
    SCAN_HILOGE("ScanServiceAbility InitScan end, scanVersion = [%{public}d]", scanVersion);
    return E_SCAN_NONE;
}


int32_t ScanServiceAbility::ExitScan()
{
    ManualStart();
    if (!CheckPermission(PERMISSION_NAME_SCAN)) {
        SCAN_HILOGE("no permission to access scan service");
        return E_SCAN_NO_PERMISSION;
    }

    SCAN_HILOGE("ScanServiceAbility ExitScan start");
    sane_exit();
    SCAN_HILOGE("ScanServiceAbility ExitScan end");
    return E_SCAN_NONE;
}

int32_t ScanServiceAbility::GetScannerList()
{
    ManualStart();
    if (!CheckPermission(PERMISSION_NAME_SCAN)) {
        SCAN_HILOGE("no permission to access scan service");
        return E_SCAN_NO_PERMISSION;
    }
    SCAN_HILOGE("ScanServiceAbility GetScannerList start");
    
    std::lock_guard<std::mutex> autoLock(lock_);
    //tcp
    auto exec_tcp = [=](){
        ScanMdnsService::GetInstance().SetServiceType("_scanner._tcp");
        ScanMdnsService::GetInstance().onStartDiscoverService();
    };
    //libusb
    auto exec_usb = [=](){
        const SANE_Device **device_list;
        SANE_Status get_devices_status = sane_get_devices(&device_list,SANE_FALSE);
        if(get_devices_status != SANE_STATUS_GOOD){
            SCAN_HILOGE("sane_get_devices failed, reason: [%{public}s]", sane_strstatus(get_devices_status));
            return;
        }
        for(const SANE_Device **current_device = device_list;*current_device!=nullptr;++current_device) {
            ScanDeviceInfoLibUSB info;
            info.deviceName = (*current_device)->name;
            info.manufacturer = (*current_device)->vendor;
            info.model = (*current_device)->model;
            info.deviceType = (*current_device)->type;
            SendDeviceInfoLibUSB(info,SCAN_DEVICE_FOUND_LIBUSB);
            SCAN_HILOGE("GetScannerList name:[%{public}s]", (*current_device)->name);
        }
    };
    serviceHandler_->PostTask(exec_tcp,ASYNC_CMD_DELAY);
    serviceHandler_->PostTask(exec_usb,ASYNC_CMD_DELAY);
    SCAN_HILOGE("ScanServiceAbility GetScannerList end");

    return E_SCAN_NONE;
}

int32_t ScanServiceAbility::StopDiscover()
{
    ManualStart();
    if (!CheckPermission(PERMISSION_NAME_SCAN)) {
        SCAN_HILOGE("no permission to access scan service");
        return E_SCAN_NO_PERMISSION;
    }
    SCAN_HILOGE("ScanServiceAbility StopDiscover start");
    
    ScanMdnsService::GetInstance().onStopDiscoverService();

    SCAN_HILOGE("ScanServiceAbility StopDiscover end");
    return E_SCAN_NONE;
}

int32_t ScanServiceAbility::OpenScanner(const std::string scannerId)
{
    ManualStart();
    std::lock_guard<std::mutex> autoLock(lock_);
    if (!CheckPermission(PERMISSION_NAME_SCAN)) {
        SCAN_HILOGE("no permission to access scan service");
        return E_SCAN_NO_PERMISSION;
    }

    SCAN_HILOGE("ScanServiceAbility OpenScanner start");
    if (scannerHandleList_.find(scannerId) != scannerHandleList_.end()) {
        SCAN_HILOGE("ScannerId: [%{public}s] is already openned!!!", scannerId.c_str());
        return E_SCAN_NONE;
    }
    SANE_Handle scannerHandle = 0;
    SANE_Status status = sane_open(scannerId.c_str(), &scannerHandle);
    if (status != SANE_STATUS_GOOD) {
        SCAN_HILOGE("sane_open failed, reason: [%{public}s]", sane_strstatus(status));
        return ScanUtil::ConvertErro(status);
    }
    scannerHandleList_.insert(std::make_pair(scannerId, scannerHandle));
    SCAN_HILOGE("ScanServiceAbility OpenScanner end");
    return E_SCAN_NONE;
}


int32_t ScanServiceAbility::CloseScanner(const std::string scannerId)
{
    ManualStart();
    std::lock_guard<std::mutex> autoLock(lock_);
    if (!CheckPermission(PERMISSION_NAME_SCAN)) {
        SCAN_HILOGE("no permission to access scan service");
        return E_SCAN_NO_PERMISSION;
    }

    SCAN_HILOGE("ScanServiceAbility CloseScanner start");
    auto scannerIt = scannerHandleList_.find(scannerId);
    if (scannerIt == scannerHandleList_.end()) {
        SCAN_HILOGE("ScannerId: [%{public}s] is not openned!!!", scannerId.c_str());
        return E_SCAN_INVALID_PARAMETER;
    }
    SANE_Handle scannerHandle = scannerHandleList_[scannerId];
    sane_close(scannerHandle);
    scannerHandleList_.erase(scannerIt);
    SCAN_HILOGE("ScanServiceAbility CloseScanner end");
    return E_SCAN_NONE;
}

int32_t ScanServiceAbility::GetScanOptionDesc(const std::string scannerId, const int32_t optionIndex, ScanOptionDescriptor &desc)
{
    ManualStart();
    std::lock_guard<std::mutex> autoLock(lock_);
    if (!CheckPermission(PERMISSION_NAME_SCAN)) {
        SCAN_HILOGE("no permission to access scan service");
        return E_SCAN_NO_PERMISSION;
    }

    SCAN_HILOGE("ScanServiceAbility GetScanOptionDesc start");
    SANE_Handle scannerHandle = nullptr;
    
    auto scannerIt = scannerHandleList_.find(scannerId);
    if (scannerIt == scannerHandleList_.end()) {
        SCAN_HILOGE("ScannerId: [%{public}s] is not openned!!!", scannerId.c_str());
        return E_SCAN_NONE;
    }
    scannerHandle = scannerHandleList_[scannerId];
    const SANE_Option_Descriptor * optionDesc;
    optionDesc = sane_get_option_descriptor(scannerHandle, optionIndex);
    if (optionDesc == nullptr) {
        SCAN_HILOGE("sane_get_option_descriptor failed, ScannerId: [%{public}s]", scannerId.c_str());
        return E_SCAN_INVALID_PARAMETER;
    }
    
    desc.SetOptionName(std::string(optionDesc->name));
    desc.SetOptionTitle(std::string(optionDesc->title));
    desc.SetOptionDesc(std::string(optionDesc->desc));
    desc.SetOptionType(optionDesc->type);
    desc.SetOptionUnit(optionDesc->unit);
    desc.SetOptionSize(optionDesc->size);
    desc.SetOptionCap(optionDesc->cap);
    desc.SetOptionConstraintType(optionDesc->constraint_type);
    if (optionDesc->constraint_type == SANE_CONSTRAINT_RANGE) {
        ScanRange scanRange;
        scanRange.SetMinValue(optionDesc->constraint.range->min);
        scanRange.SetMaxValue(optionDesc->constraint.range->max);
        scanRange.SetQuantValue(optionDesc->constraint.range->quant);
        desc.SetOptionConstraintRange(scanRange);
    } else if (optionDesc->constraint_type == SANE_CONSTRAINT_WORD_LIST) {
        std::vector<int32_t> optionConstraintNumber;
        int sizeNumber = *(optionDesc->constraint.word_list) + 1;
        for (int i=0; i<sizeNumber; i++) {
            SCAN_HILOGE("SANE_CONSTRAINT_WORD_LIST: %d", *(optionDesc->constraint.word_list+i));
            optionConstraintNumber.push_back(*(optionDesc->constraint.word_list+i));
        }
        desc.SetOptionConstraintNumber(optionConstraintNumber);
    } else if (optionDesc->constraint_type == SANE_CONSTRAINT_STRING_LIST) {
        std::vector<std::string> optionConstraintString;
        for (int i=0; *(optionDesc->constraint.string_list+i) != NULL; i++) {
            SCAN_HILOGE("SANE_CONSTRAINT_STRING_LIST: %s", *(optionDesc->constraint.string_list+i));
            optionConstraintString.push_back(string(*(optionDesc->constraint.string_list+i)));
        }
        optionConstraintString.push_back(string("null"));
        desc.SetOptionConstraintString(optionConstraintString);
    }
    SCAN_HILOGE("ScanServiceAbility GetScanOptionDesc end");
    return E_SCAN_NONE;
}

int32_t ScanServiceAbility::OpScanOptionValue(const std::string scannerId, const int32_t optionIndex, const ScanOptionOpType op, ScanOptionValue &value, int32_t &info)
{
    ManualStart();
    std::lock_guard<std::mutex> autoLock(lock_);
    if (!CheckPermission(PERMISSION_NAME_SCAN)) {
        SCAN_HILOGE("no permission to access scan service");
        return E_SCAN_NO_PERMISSION;
    }

    SCAN_HILOGE("ScanServiceAbility OpScanOptionValue start");
    auto scannerIt = scannerHandleList_.find(scannerId);
    if (scannerIt == scannerHandleList_.end()) {
        SCAN_HILOGE("ScannerId: [%{public}s] is not openned!!!", scannerId.c_str());
        return E_SCAN_INVALID_PARAMETER;
    }
    SANE_Handle scannerHandle = scannerHandleList_[scannerId];
    SCAN_HILOGE("ScanServiceAbility OpScanOptionValue start to dump value");
    value.Dump();
    
    SANE_Status status = SANE_STATUS_GOOD;
    if (op == SCAN_ACTION_SET_AUTO) {
        status = sane_control_option(scannerHandle, optionIndex, SANE_ACTION_SET_AUTO, 0, 0);
        if (status != SANE_STATUS_GOOD) {
            SCAN_HILOGE("sane_control_option failed, reason: [%{public}s]", sane_strstatus(status));
            return ScanUtil::ConvertErro(status);
        }
    }
    else {
        void *saneValueBuf;
        int32_t bufSize = value.GetValueSize() / sizeof(SANE_Word);
        ScanOptionValueType valueType = value.GetScanOptionValueType();
        saneValueBuf = alloca(bufSize);
        if (!saneValueBuf) {
            SCAN_HILOGE("alloca value buffer failed");
            return E_SCAN_GENERIC_FAILURE;
        }

        if (op == SCAN_ACTION_GET_VALUE) {        
            status = sane_control_option(scannerHandle, optionIndex, SANE_ACTION_GET_VALUE, saneValueBuf, 0);
            if (status != SANE_STATUS_GOOD) {
                SCAN_HILOGE("sane_control_option failed, reason: [%{public}s]", sane_strstatus(status));
                return ScanUtil::ConvertErro(status);
            }

            if (valueType == SCAN_VALUE_NUM) {
                value.SetNumValue(*(int *)saneValueBuf);
            }
            else if (valueType == SCAN_VALUE_NUM_LIST) {
                std::vector<int32_t> numListValue;
                for (int i=0; i<bufSize; i++){
                    numListValue.emplace_back(*((int32_t *)saneValueBuf+i));
                }
                value.SetNumListValue(numListValue);
            }
            else if (valueType == SCAN_VALUE_STR) {
                value.SetStrValue(string((char *) saneValueBuf));
            }
            else if (valueType == SCAN_VALUE_BOOL) {
                value.SetBoolValue(*(int32_t *) saneValueBuf > 0 ? true : false);
            }
        }
        else if (op == SCAN_ACTION_SET_VALUE) {
            if (valueType == SCAN_VALUE_NUM) {
                *(int *)saneValueBuf = value.GetNumValue();
            }
            else if (valueType == SCAN_VALUE_NUM_LIST) {
                std::vector<int32_t> numListValue;
                value.GetNumListValue(numListValue);
                for (int i=0; i<bufSize; i++){
                    *((int32_t *)saneValueBuf+i) = numListValue[i];
                }            
            }
            else if (valueType == SCAN_VALUE_STR) {
                strcpy((char *) saneValueBuf, value.GetStrValue().c_str());
            }
            else if (valueType == SCAN_VALUE_BOOL) {
                *(int32_t *) saneValueBuf = value.GetBoolValue() > 0 ? true : false;
            }
            status = sane_control_option(scannerHandle, optionIndex, SANE_ACTION_SET_VALUE, saneValueBuf, &info);
            if (status != SANE_STATUS_GOOD) {
                SCAN_HILOGE("sane_control_option failed, reason: [%{public}s]", sane_strstatus(status));
                return ScanUtil::ConvertErro(status);
            }
        }
    }
    value.Dump();
    SCAN_HILOGE("ScanServiceAbility OpScanOptionValue end");
    return E_SCAN_NONE;
}

int32_t ScanServiceAbility::GetScanParameters(const std::string scannerId, ScanParameters &para)
{
    ManualStart();
    std::lock_guard<std::mutex> autoLock(lock_);
    if (!CheckPermission(PERMISSION_NAME_SCAN)) {
        SCAN_HILOGE("no permission to access scan service");
        return E_SCAN_NO_PERMISSION;
    }

    SCAN_HILOGE("ScanServiceAbility GetScanParameters start");
    auto scannerIt = scannerHandleList_.find(scannerId);
    if (scannerIt == scannerHandleList_.end()) {
        SCAN_HILOGE("ScannerId: [%{public}s] is not openned!!!", scannerId.c_str());
        return E_SCAN_INVALID_PARAMETER;
    }
    SANE_Handle scannerHandle = scannerHandleList_[scannerId];
    SANE_Parameters parameters;
    SANE_Status status = sane_get_parameters(scannerHandle, &parameters);
    if (status != SANE_STATUS_GOOD) {
        SCAN_HILOGE("sane_get_parameters failed, reason: [%{public}s]", sane_strstatus(status));
        return ScanUtil::ConvertErro(status);
    }
    para.SetFormat((ScanFrame)parameters.format);
    para.SetLastFrame((bool)parameters.last_frame);
    para.SetBytesPerLine(parameters.bytes_per_line);
    para.SetPixelsPerLine(parameters.pixels_per_line);
    para.SetLines(parameters.lines);
    para.SetDepth(parameters.depth);
    
    SCAN_HILOGE("ScanServiceAbility GetScanParameters end");
    return E_SCAN_NONE;
}

int32_t ScanServiceAbility::StartScan(const std::string scannerId)
{
    ManualStart();
    std::lock_guard<std::mutex> autoLock(lock_);
    if (!CheckPermission(PERMISSION_NAME_SCAN)) {
        SCAN_HILOGE("no permission to access scan service");
        return E_SCAN_NO_PERMISSION;
    }

    SCAN_HILOGE("ScanServiceAbility StartScan start");
    auto scannerIt = scannerHandleList_.find(scannerId);
    if (scannerIt == scannerHandleList_.end()) {
        SCAN_HILOGE("ScannerId: [%{public}s] is not openned!!!", scannerId.c_str());
        return E_SCAN_INVALID_PARAMETER;
    }
    SANE_Handle scannerHandle = scannerHandleList_[scannerId];
    SANE_Status status = sane_start(scannerHandle);
    if (status != SANE_STATUS_GOOD) {
        SCAN_HILOGE("sane_start failed, reason: [%{public}s]", sane_strstatus(status));
        return ScanUtil::ConvertErro(status);
    }
    SCAN_HILOGE("ScanServiceAbility StartScan end");
    return E_SCAN_NONE;
}

int32_t ScanServiceAbility::GetSingleFrame(const std::string scannerId, int32_t &size, uint8_t **frameData)
{
    ManualStart();
    std::lock_guard<std::mutex> autoLock(lock_);
    if (!CheckPermission(PERMISSION_NAME_SCAN)) {
        SCAN_HILOGE("no permission to access scan service");
        return E_SCAN_NO_PERMISSION;
    }

    SCAN_HILOGE("ScanServiceAbility GetSingleFrame start");
    auto scannerIt = scannerHandleList_.find(scannerId);
    if (scannerIt == scannerHandleList_.end()) {
        SCAN_HILOGE("ScannerId: [%{public}s] is not openned!!!", scannerId.c_str());
        return E_SCAN_INVALID_PARAMETER;
    }
    SANE_Handle scannerHandle = scannerHandleList_[scannerId];
    int32_t data_size = buffer_size;
    uint8_t* data = nullptr;
    data = (uint8_t *)malloc(data_size);
    if (!data) {
        SCAN_HILOGE("malloc memory for data failed!!!");
        return E_SCAN_NO_MEM;
    }
    uint8_t* buffer = (uint8_t *) malloc(buffer_size);
    if (!buffer) {
        SCAN_HILOGE("malloc memory for buffer failed!!!");
        return E_SCAN_NO_MEM;
    }
    int32_t totalReadSize = 0;
    int32_t curReadSize = 0;
    SANE_Status status = SANE_STATUS_GOOD;
    while (true) {
        status = sane_read(scannerHandle, buffer, buffer_size, &curReadSize);
        if (status != SANE_STATUS_GOOD) {
            if (status != SANE_STATUS_EOF) {
                if (buffer) {
                    free(buffer);
                }
                SCAN_HILOGE("sane_read failed, reason: [%{public}s]", sane_strstatus(status));
                return ScanUtil::ConvertErro(status);
            }
            break;            
        }
        SCAN_HILOGE("sane_read success, read %{public}d bytes data", curReadSize);
        if (totalReadSize + curReadSize > data_size) {
            data_size += buffer_size;
            data = (uint8_t *)realloc(data, data_size);
            if (!data) {
                free(data);
                if (buffer) {
                    free(buffer);
                }
                SCAN_HILOGE("malloc memory for data failed!!!");
                return E_SCAN_NO_MEM;
            }
            SCAN_HILOGE("data_size changes to %{public}d", data_size);
        }
        memcpy_s(data+totalReadSize, data_size-totalReadSize, buffer, curReadSize);
        totalReadSize += curReadSize;
    }
    size = totalReadSize;
    *frameData = data; 
    SCAN_HILOGE("Totally read %{public}d bytes of frame data", size);
    if (buffer) {
        free(buffer);
    }
    SCAN_HILOGE("ScanServiceAbility GetSingleFrame end");
    return E_SCAN_NONE;
}

int32_t ScanServiceAbility::GetSingleFrameFD(const std::string scannerId, int32_t &size, uint32_t fd)
{
    ManualStart();
    std::lock_guard<std::mutex> autoLock(lock_);
    if (!CheckPermission(PERMISSION_NAME_SCAN)) {
        SCAN_HILOGE("no permission to access scan service");
        return E_SCAN_NO_PERMISSION;
    }


    SCAN_HILOGE("ScanServiceAbility GetSingleFrameFD start");
    auto scannerIt = scannerHandleList_.find(scannerId);
    if (scannerIt == scannerHandleList_.end()) {
        SCAN_HILOGE("ScannerId: [%{public}s] is not openned!!!", scannerId.c_str());
        return E_SCAN_INVALID_PARAMETER;
    }
    SANE_Handle scannerHandle = scannerHandleList_[scannerId];

    auto exec = [=]() {
        int32_t totalReadSize = 0;
        int32_t curReadSize = 0;
        uint8_t* buffer = (uint8_t *) malloc(buffer_size);
        if (!buffer) {
            SCAN_HILOGE("malloc memory for buffer failed!!!");
            SendGetFrameResEvent(false, totalReadSize);
            return;
        }
        SANE_Status status = SANE_STATUS_GOOD;
        while (true) {
            status = sane_read(scannerHandle, buffer, buffer_size, &curReadSize);
            if (status != SANE_STATUS_GOOD) {
                if (status != SANE_STATUS_EOF) {
                    if (buffer) {
                        free(buffer);
                    }
                    SCAN_HILOGE("sane_read failed, reason: [%{public}s]", sane_strstatus(status));
                    SendGetFrameResEvent(false, totalReadSize);
                    return;
                }
                break;            
            }   
            write(fd, buffer, curReadSize);
            totalReadSize += curReadSize;
            SCAN_HILOGE("sane_read success, current read: %{public}d Bytes, already read %{public}d Bytes", curReadSize, totalReadSize);
        }
        SCAN_HILOGE("Totally read %{public}d bytes of frame data", totalReadSize);
        if (buffer) {
            free(buffer);
        }
        SendGetFrameResEvent(true, totalReadSize);
    };
    serviceHandler_->PostTask(exec, ASYNC_CMD_DELAY);
    
    SCAN_HILOGE("ScanServiceAbility GetSingleFrameFD end");
    return E_SCAN_NONE;
}

int32_t ScanServiceAbility::CancelScan(const std::string scannerId)
{
    ManualStart();
    std::lock_guard<std::mutex> autoLock(lock_);
    if (!CheckPermission(PERMISSION_NAME_SCAN)) {
        SCAN_HILOGE("no permission to access scan service");
        return E_SCAN_NO_PERMISSION;
    }

    SCAN_HILOGE("ScanServiceAbility CancelScan start");
    auto scannerIt = scannerHandleList_.find(scannerId);
    if (scannerIt == scannerHandleList_.end()) {
        SCAN_HILOGE("ScannerId: [%{public}s] is not openned!!!", scannerId.c_str());
        return E_SCAN_INVALID_PARAMETER;
    }
    SANE_Handle scannerHandle = scannerHandleList_[scannerId];
    sane_cancel(scannerHandle);
    SCAN_HILOGE("ScanServiceAbility CancelScan end");
    return E_SCAN_NONE;
}

int32_t ScanServiceAbility::SetScanIOMode(const std::string scannerId, const bool isNonBlocking)
{
    ManualStart();
    std::lock_guard<std::mutex> autoLock(lock_);
    if (!CheckPermission(PERMISSION_NAME_SCAN)) {
        SCAN_HILOGE("no permission to access scan service");
        return E_SCAN_NO_PERMISSION;
    }

    SCAN_HILOGE("ScanServiceAbility SetScanIOMode start");
    auto scannerIt = scannerHandleList_.find(scannerId);
    if (scannerIt == scannerHandleList_.end()) {
        SCAN_HILOGE("ScannerId: [%{public}s] is not openned!!!", scannerId.c_str());
        return E_SCAN_INVALID_PARAMETER;
    }
    SANE_Handle scannerHandle = scannerHandleList_[scannerId];
    SANE_Status status = sane_set_io_mode(scannerHandle, isNonBlocking);
    if (status != SANE_STATUS_GOOD) {
        SCAN_HILOGE("sane_set_io_mode failed, reason: [%{public}s]", sane_strstatus(status));
        return ScanUtil::ConvertErro(status);
    }
    SCAN_HILOGE("ScanServiceAbility SetScanIOMode end");
    return E_SCAN_NONE;
}

int32_t ScanServiceAbility::GetScanSelectFd(const std::string scannerId, int32_t &fd)
{
    ManualStart();
    std::lock_guard<std::mutex> autoLock(lock_);
    if (!CheckPermission(PERMISSION_NAME_SCAN)) {
        SCAN_HILOGE("no permission to access scan service");
        return E_SCAN_NO_PERMISSION;
    }

    SCAN_HILOGE("ScanServiceAbility GetScanSelectFd start");
    auto scannerIt = scannerHandleList_.find(scannerId);
    if (scannerIt == scannerHandleList_.end()) {
        SCAN_HILOGE("ScannerId: [%{public}s] is not openned!!!", scannerId.c_str());
        return E_SCAN_INVALID_PARAMETER;
    }
    SANE_Handle scannerHandle = scannerHandleList_[scannerId];
    SANE_Status status = sane_get_select_fd(scannerHandle, &fd);
    if (status != SANE_STATUS_GOOD) {
        SCAN_HILOGE("sane_set_io_mode failed, reason: [%{public}s]", sane_strstatus(status));
        return ScanUtil::ConvertErro(status);
    }
    SCAN_HILOGE("ScanServiceAbility GetScanSelectFd end");
    return E_SCAN_NONE;
}

int32_t ScanServiceAbility::On(const std::string taskId, const std::string &type, const sptr<IScanCallback> &listener)
{
    std::string permission = PERMISSION_NAME_SCAN_JOB;
    std::string eventType = type;
    if (taskId != "") {
        permission = PERMISSION_NAME_SCAN;
        eventType = NapiScanUtils::GetTaskEventId(taskId, type);
    }
    if (!CheckPermission(PERMISSION_NAME_SCAN)) {
        SCAN_HILOGE("no permission to access scan service");
        return E_SCAN_NO_PERMISSION;
    }

    SCAN_HILOGD("ScanServiceAbility::On started. type=%{public}s", eventType.c_str());
    std::lock_guard<std::recursive_mutex> lock(apiMutex_);
    if (registeredListeners_.find(eventType) == registeredListeners_.end()) {
        const auto temp = registeredListeners_.insert(std::make_pair(eventType, listener));
        if (!temp.second) {
            SCAN_HILOGE("ScanServiceAbility::On insert type=%{public}s object fail.", eventType.c_str());
            return E_SCAN_SERVER_FAILURE;
        }
    } else {
        SCAN_HILOGD("ScanServiceAbility::On Replace listener.");
        registeredListeners_[eventType] = listener;
    }
    SCAN_HILOGD("ScanServiceAbility::On end.");
    return E_SCAN_NONE;
}

int32_t ScanServiceAbility::Off(const std::string taskId, const std::string &type)
{
    std::string permission = PERMISSION_NAME_SCAN_JOB;
    std::string eventType = type;
    if (taskId != "") {
        permission = PERMISSION_NAME_SCAN;
        eventType = NapiScanUtils::GetTaskEventId(taskId, type);
    }
    if (!CheckPermission(PERMISSION_NAME_SCAN)) {
        SCAN_HILOGE("no permission to access scan service");
        return E_SCAN_NO_PERMISSION;
    }

    SCAN_HILOGD("ScanServiceAbility::Off started.");
    std::lock_guard<std::recursive_mutex> lock(apiMutex_);
    auto iter = registeredListeners_.find(eventType);
    if (iter != registeredListeners_.end()) {
        SCAN_HILOGD("ScanServiceAbility::Off delete type=%{public}s object message.", eventType.c_str());
        registeredListeners_.erase(iter);
        return E_SCAN_NONE;
    }
    return E_SCAN_INVALID_PARAMETER;
}


void ScanServiceAbility::SendGetFrameResEvent(const bool isGetSucc, const int32_t sizeRead)
{
    std::lock_guard<std::recursive_mutex> lock(apiMutex_);
    SCAN_HILOGE("ScanServiceAbility::SendGetFrameSuccEvent SizeRead %{public}d", sizeRead);
    auto eventIt = registeredListeners_.find(GET_FRAME_RES_EVENT_TYPE);
    if (eventIt != registeredListeners_.end()) {
        eventIt->second->OnGetFrameResCallback(isGetSucc, sizeRead);
    } else {
        SCAN_HILOGE("%{public}s event not register", GET_FRAME_RES_EVENT_TYPE.c_str());
    }
}

void ScanServiceAbility::SendDeviceInfoTCP(const ScanDeviceInfoTCP &info,std::string event){
    std::lock_guard<std::recursive_mutex> lock(apiMutex_);
    auto eventIt = registeredListeners_.find(event);
    if (eventIt != registeredListeners_.end()) {
        SCAN_HILOGE("GetScannerListSendDeviceInfoTCP event has registered");
        eventIt->second->OnCallback(info.GetDeviceState(), info);
    } else {
        SCAN_HILOGE("GetScannerList SendDeviceInfoTCP event not register");
    }
}

void ScanServiceAbility::SendDeviceInfoLibUSB(const ScanDeviceInfoLibUSB &info,std::string event){
    std::lock_guard<std::recursive_mutex> lock(apiMutex_);
    auto eventIt = registeredListeners_.find(event);
    if (eventIt != registeredListeners_.end()) {
        SCAN_HILOGE("GetScannerListSendDeviceInfoTCP event has registered");
        eventIt->second->OnCallback(info.GetDeviceState(), info);
    } else {
        SCAN_HILOGE("GetScannerList SendDeviceInfoTCP event not register");
    }
}
void ScanServiceAbility::SendInitEvent(int32_t &scanVersion,std::string event){
    std::lock_guard<std::recursive_mutex> lock(apiMutex_);
    auto eventIt = registeredListeners_.find(event);
    if (eventIt != registeredListeners_.end()) {
        SCAN_HILOGE("InitScan SendInitEvent event has registered");
        eventIt->second->OnScanInitCallback(scanVersion);
    } else {
        SCAN_HILOGE("InitScan SendInitEvent event not register");
    }    
}

bool ScanServiceAbility::CheckPermission(const std::string &permissionName)
{
    return true;
}

}

